package org.mayanjun.code.easyweb.springmvc.config;

import org.apache.commons.lang.ArrayUtils;
import org.mayanjun.code.easyweb.springmvc.annotation.ScanIgnore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.*;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

import javax.annotation.PostConstruct;

/**
 * ServletApplicationConfig is a configuration class to scan all the resources which specified in web.properties file.
 * You can reference the Resource[] bean with name {@link Global#BEAN_NAME_ALL_PROPS_RESOURCES}, you can also use the @Value
 * annotation to inject a property to a member of bean because of all the properties is set to an {@link PropertiesFactoryBean} bean.
 * <div style="color:red">
 *     Note that this configuration bean is depend on {@link WebMvcApplicationConfig}
 * </div>
 *
 * @author mayanjun(11/10/15)
 */
@Configuration
@EnableWebMvc
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ComponentScan(basePackages = "${" + WebPropertiesNames.SPRING_SCAN_PACKAGES + ":" + Global.DEFAULT_SCAN_PACKAGE  +"}", excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, value = ScanIgnore.class)
})
@ImportResource("classpath:${" + WebPropertiesNames.SPRING_SCAN_XML + ":" + Global.DEFAULT_SCAN_XML + "}")
@PropertySource(value = "classpath:${" + WebPropertiesNames.SPRING_SCAN_PROPS + ":" + Global.DEFAULT_SCAN_PROPS + "}", ignoreResourceNotFound = true)
@ScanIgnore
public class ServletApplicationConfig implements ResourceLoaderAware {

    private static final Logger LOG = LoggerFactory.getLogger(ServletApplicationConfig.class);

    private static String ERROR_PAGE;

    private static PropertiesResourcesLogger propertiesResourcesLogger = new PropertiesResourcesLogger(LOG);

    private ResourceLoader resourceLoader;

    @Value("#{" + Global.BEAN_NAME_ROOT_PROPS + "['" + WebPropertiesNames.SPRING_SCAN_PACKAGES + "']}")
    private String springPackageScan;

    @Value("#{" + Global.BEAN_NAME_ROOT_PROPS + "['" + WebPropertiesNames.SPRING_SCAN_XML + "']}")
    private String springXmlScan;

    @Value("#{" + Global.BEAN_NAME_ROOT_PROPS + "['" + WebPropertiesNames.ERROR_PAGE + "']}")
    private String errorPage;

    @Value("#{" + Global.BEAN_NAME_ROOT_PROPS + "['" + WebPropertiesNames.SPRING_SCAN_PROPS + "']}")
    private String springPropsScan;

    public static String getErrorPage() {
        return ERROR_PAGE;
    }

    /**
     * Print the effective value to be used
     */
    @PostConstruct
    private void log() {
        LOG.info("Using web props '" + WebPropertiesNames.SPRING_SCAN_PACKAGES + "'=" + (springPackageScan == null ? Global.DEFAULT_SCAN_PACKAGE + "(default)" : springPackageScan));
        LOG.info("Using web props '" + WebPropertiesNames.SPRING_SCAN_XML + "'=" + (springXmlScan == null ? Global.DEFAULT_SCAN_XML + "(default)" : springXmlScan));
        LOG.info("Using web props '" + WebPropertiesNames.SPRING_SCAN_PROPS + "'=" + (springPropsScan == null ? Global.DEFAULT_SCAN_PROPS + "(default)" : springPropsScan));
        ERROR_PAGE = (errorPage == null ? Global.DEFAULT_ERROR_PAGE : errorPage);
        LOG.info("Using web props '" + WebPropertiesNames.ERROR_PAGE + "'=" + (errorPage == null ? Global.DEFAULT_ERROR_PAGE + "(default)" : errorPage));
    }

    @Bean(name = Global.BEAN_NAME_ALL_PROPS)
    public PropertiesFactoryBean getPropertiesFactoryBean() throws Exception {
        PropertiesFactoryBean bean = new PropertiesFactoryBean();
        bean.setIgnoreResourceNotFound(true);
        bean.setLocations(getAllResources());
        return bean;
    }

    @Bean(name = Global.BEAN_NAME_ALL_PROPS_RESOURCES)
    public Resource[] getAllResources() throws Exception {
        String userProps = "classpath:" + (springPropsScan == null ? Global.DEFAULT_SCAN_PROPS : springPropsScan);
        ResourcePatternResolver rpr = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
        Resource res[] = rpr.getResources(userProps);
        Resource root[] = WebMvcApplicationConfig.getPropsResources(resourceLoader);

        Resource all[] = (Resource[])ArrayUtils.addAll(res, root);
        propertiesResourcesLogger.log(Global.BEAN_NAME_ALL_PROPS, res);
        return all;
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }
}